#include "device/device.h"
#include "log/Logger.h"
#include "config/ConfigManager.h"
#include <iostream>
#include <stdio.h>
#include <time.h>
#include <chrono>
#include <stdlib.h>
#include<sys/socket.h>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<error.h>
#include<math.h>
#include<ctype.h>
#include<sys/time.h>
#include<sys/stat.h>
#include<sys/vfs.h>
#include<sys/param.h>
#include <algorithm>
#include <ratio>
#include<ctime>
std::mutex g_CDeviceMtx;
CDevieStatus *CDevieStatus::m_pInstance = nullptr;
CDevieStatus* CDevieStatus::GetInstance()
{   
    if(m_pInstance == nullptr)
    {
        g_CDeviceMtx.lock();
        if (m_pInstance == nullptr)
        {
            m_pInstance = new CDevieStatus();
        }
        g_CDeviceMtx.unlock();
        return  m_pInstance;
    }
    else
    {
        return  m_pInstance; 
    }
}

CDevieStatus::CDevieStatus()
{

}
//析构函数，析构
CDevieStatus::~CDevieStatus()
{
    if(m_pThread != nullptr)
    {
        m_pThread = nullptr;
    }
}

void CDevieStatus::init()
{
    m_pThread = new std::thread(&CDevieStatus::Proc, this);
}

//开启线程
void CDevieStatus::Proc()
{
    MEM_OCCUPY mem_stat;
    CPU_OCCUPY cpu_stat1;
    CPU_OCCUPY cpu_stat2;
    while(true)
    {
        GetMemOccupy((MEM_OCCUPY *)&mem_stat);
        mem_stat.dump();
        printf(" [MemTotal] = %lu \n [MemFree] = %lu \n [Buffers] = %lu \n [Cached] = %lu \n [SwapCached] = %lu \n", mem_stat.MemTotal, mem_stat.MemFree, mem_stat.Buffers, mem_stat.Cached, mem_stat.SwapCached);
        GetCpuOccupy((CPU_OCCUPY *)&cpu_stat1);
        GetCpuOccupy((CPU_OCCUPY *)&cpu_stat2);
        CalCpuOccupy((CPU_OCCUPY *)&cpu_stat1,(CPU_OCCUPY *)&cpu_stat2);
    }
}

//对无类型的get函数含有一个形参结构体类的指针
void CDevieStatus::GetMemOccupy(MEM_OCCUPY *mem)
{
    FILE *fd;
    char buff[256];
    MEM_OCCUPY *m;
    m = mem;
    fd = fopen("/pro/meminfo", "r");

    fgets(buff, sizeof(buff), fd);
    sscanf(buff, "%s %u ", m->name1, &m->MemTotal);

    fgets(buff, sizeof(buff), fd);
    sscanf(buff, "%s %lu", m->name2, &m->MemFree);

    fgets(buff, sizeof(buff), fd);
    sscanf(buff, "%s %lu", m->name3, &m->Buffers);

    fgets(buff, sizeof(buff), fd);
    sscanf(buff, "%s %lu",  m->name4, &m->Cached);
    
    fgets(buff, sizeof(buff), fd);
    sscanf(buff, "%s %lu", m->name5, &m->SwapCached);

    fclose(fd); //关闭文件fd
}

void  CDevieStatus::GetCpuOccupy(CPU_OCCUPY *cpust)
{
    FILE *fd;
    char buff[256];
    CPU_OCCUPY *cpu_occupy;
    cpu_occupy = cpust;
 
    fd = fopen("/proc/stat", "r");
    fgets(buff, sizeof(buff), fd);
    sscanf(buff, "%s %u %u %u %u %u %u %u", cpu_occupy->name, &cpu_occupy->user, &cpu_occupy->nice, &cpu_occupy->system, &cpu_occupy->idle, &cpu_occupy->lowait, &cpu_occupy->irq, &cpu_occupy->softirq);
 
    fclose(fd);
 
    return;
}

void CDevieStatus::CalCpuOccupy(CPU_OCCUPY *o, CPU_OCCUPY *n)
{
    unsigned long od, nd;
    double cpu_use = 0;
 
    od = (unsigned long)(o->user + o->nice + o->system + o->idle + o->lowait + o->irq + o->softirq);//第一次(用户+优先级+系统+空闲)的时间再赋给od
    nd = (unsigned long)(n->user + n->nice + n->system + n->idle + n->lowait + n->irq + n->softirq);//第二次(用户+优先级+系统+空闲)的时间再赋给od
    double sum = nd - od;
    double idle = n->idle - o->idle;
    cpu_use = idle / sum;
    //printf("cpu_use1(idle) = %f\r\n", cpu_use);
    LOG_INFO("cpu_use1(idle) = "  <<  cpu_use);
    idle = n->user + n->system + n->nice - o->user - o->system - o->nice;
    cpu_use = idle / sum;
   // printf("cpu_use2(user+system+nice) = %f\r\n", cpu_use);
    LOG_INFO("cpu_use2(user+system+nice) = " <<  cpu_use);
    return ;
} 

void CDevieStatus::GetUsedTime()//使用时间
{

    struct timespec timestamp = { 0, 0 };
	clock_gettime(CLOCK_REALTIME, &timestamp);
	uint64_t now_epoch_time = timestamp.tv_sec * 1000000000 + timestamp.tv_nsec;
    LOG_INFO(" Current epoch Time: " << now_epoch_time/1000000000 << "s");


	clock_gettime(CLOCK_MONOTONIC, &timestamp);
	uint64_t machine_running_duration = timestamp.tv_sec * 1000000000 + timestamp.tv_nsec;
    LOG_INFO("machine running to now duration: " << machine_running_duration/ 1000000000  << " s ");

	uint64_t launch_epoch_time = now_epoch_time - machine_running_duration;
    LOG_INFO("machine launch epoch time: " << launch_epoch_time / 1000000000  << " s"); 


    //获取系统当前时间
    struct timeval tv;
    gettimeofday(&tv, NULL);
    time_t sec = tv.tv_sec;
    suseconds_t usec = tv.tv_usec;
    struct tm *lt = localtime(&sec);

    LOG_INFO("Current Time: " << lt->tm_year + 1900  << "-" << lt->tm_mon + 1 << "-" << lt->tm_mday << "  " << 
        lt->tm_hour << ":" << lt->tm_min << ":" << lt->tm_sec );
}